package com.ybear.ybutils.utils.toast;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.Region;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ybear.ybutils.utils.R;

import java.lang.ref.WeakReference;
import java.util.Locale;

/**
 * 圆角帮助类
 */
class ToastXShapeHelper implements IToastXShape {
    private WeakReference<View> mWrView;
    private Paint mPaint;
    private PaintFlagsDrawFilter mDrawFilter;
    private PorterDuffXfermode mXfermodeShape, mXfermodeShadow, mXfermodeStroke;
    private Canvas mShapeCanvas;
    private Path mShapePath;
    private RectF mRectF;
    private boolean isRtlLayout;
    private float[] mRadii;
    private int mBorderSize;
    @ColorInt
    private int mBorderColor;
    private int mShadowRadius, mShadowOffsetX, mShadowOffsetY;
    @ColorInt
    private int mShadowColor;

    public <T extends View> ToastXShapeHelper init(@NonNull T v) {
        mWrView = new WeakReference<>( v );
        mPaint = new Paint();
        //画布抗锯齿
        mDrawFilter = new PaintFlagsDrawFilter(
                0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG
        );
        //创建绘制的画布
        mShapeCanvas = new Canvas();
        //创建绘制的路径
        mShapePath = new Path();
        //创建绘制图像的矩阵
        mRectF = new RectF();
        /* 保留上层交集图像 */ //PorterDuff.Mode.DST_IN
        mXfermodeShape = new PorterDuffXfermode( PorterDuff.Mode.DST_IN );
        //启用抗锯齿
        mPaint.setAntiAlias( true );
        //消除画布的抗锯齿
        mShapeCanvas.setDrawFilter( mDrawFilter );
        //启用硬件加速。设计器和模拟器可能依旧会存在黑边
        setEnableLayerTypeHardware( v, true );
        //启用RTL布局
        setEnableRtlLayout( Locale.getDefault() );
        v.setFocusable( false );
        return this;
    }

    @Override
    public void setEnableRtlLayout(Locale locale) {
        isRtlLayout = TextUtils.getLayoutDirectionFromLocale(
                locale
        ) == View.LAYOUT_DIRECTION_RTL;
    }

    @Override
    public void setDisableRtlLayout() {
        isRtlLayout = false;
    }

    @Override
    public void setEnableLayerTypeHardware(@NonNull View view, boolean enable) {
        int curType = view.getLayerType();
        if( enable ) {
            if( curType != View.LAYER_TYPE_HARDWARE ) {
                view.setLayerType( View.LAYER_TYPE_HARDWARE, null );
            }
            return;
        }
        if( curType != View.LAYER_TYPE_SOFTWARE ) {
            view.setLayerType( View.LAYER_TYPE_SOFTWARE, null );
        }
    }

    @Override
    public void setRadius(float lt, float rt, float lb, float rb) {
        setRadii( isRtlLayout ?
                new float[] { rt, rt, lt, lt, lb, lb, rb, rb } :
                new float[] { lt, lt, rt, rt, rb, rb, lb, lb }
        );
    }

    @Override
    public void setRadius(float r) { setRadius( r, r, r, r ); }

    @Override
    public void setRadii(float[] radii) { mRadii = radii; }

    @Nullable
    @Override
    public float[] getRadii() { return mRadii; }

    @Override
    public void setBorderSize(int borderSize) { mBorderSize = borderSize; }
    @Override
    public void setBorderColor(@ColorInt int color) { mBorderColor = color; }
    @Override
    public void setShadowRadius(int radius) { mShadowRadius = radius; }
    @Override
    public void setShadowColor(@ColorInt int color) { mShadowColor = color; }
    @Override
    public void setShadowOffsetX(int offsetX) { mShadowOffsetX = offsetX; }
    @Override
    public void setShadowOffsetY(int offsetY) { mShadowOffsetY = offsetY; }

    public void dispatchDraw(@NonNull Canvas canvas, @NonNull View v) {
        int width = v.getWidth();
        int height = v.getHeight();
        if( width <= 0 || height <= 0 ) return;
        //更新Padding
        if( paddingHash != getPaddingHash() ) {
            updatePadding();
        }
        //消除画布的抗锯齿
        canvas.setDrawFilter( mDrawFilter );
        //获取位图
        Bitmap shapeBmp = getShapeBmp( width, height );
        //绘制描边
        drawStroke( canvas, shapeBmp );
        //获取绘制圆角部分的图片
        drawShape( canvas, shapeBmp );
        //绘制阴影
        drawShadow( v.getContext(), canvas, shapeBmp );
        //回收位图
        shapeBmp.recycle();
    }

    /**
     绘制圆角部分的图片
     @param canvas          主画布
     @param shapeBmp        绘制的图片
     */
    private void drawShape(Canvas canvas, Bitmap shapeBmp) {
        Canvas shapeCanvas = getCanvas();
        //设置图片
        shapeCanvas.setBitmap( shapeBmp );
        //初始化矩形
        initRectFOfDefault( shapeBmp, mBorderSize );
        //初始化画笔
        initPaint();
        //绘制形状（传入的颜色不能是透明，任意颜色都可以，主要用于裁剪）
        drawShape( shapeCanvas, Color.BLACK );
        //绘制时消除绘制的圆角(或者注释掉看效果就明白了)
        mPaint.setXfermode( mXfermodeShape );
        //绘制最终的结果
        drawBitmap( canvas, shapeBmp );
        mPaint.setXfermode( null );
    }

    /**
     * 绘制阴影
     * @param canvas    画布
     */
    private void drawShadow(@NonNull Context context, Canvas canvas, Bitmap shapeBmp) {
        if( mShadowRadius == 0 ) return;
        int shadowColor = getShadowColor( context );
        //初始化矩形
        initRectFOfDefault( shapeBmp, 0 );
        //初始化画笔
        initPaint();
        //创建阴影
        mPaint.setShadowLayer(
                mShadowRadius, mShadowOffsetX, mShadowOffsetY, shadowColor
        );
        //绘制阴影
        drawPath( canvas );
        //关闭阴影
        mPaint.clearShadowLayer();
    }

    /**
     * 绘制描边
     * @param canvas    画布
     */
    private void drawStroke(Canvas canvas, Bitmap shapeBmp) {
        if( mBorderSize == 0 ) return;
        Canvas strokeCanvas = getCanvas();
        //设置图片
        strokeCanvas.setBitmap( shapeBmp );
        //初始化矩形
        initRectFOfDefault( shapeBmp, 0 );
        //初始化画笔
        initPaint();
        mPaint.setStyle( Paint.Style.STROKE );
        mPaint.setStrokeWidth( mBorderSize * 2 );
        drawShape( canvas, mBorderColor );
    }

    /**
     * 绘制形状/路径
     * @param canvas        画布
     * @param paintColor    画笔颜色
     */
    private void drawShape(Canvas canvas, @ColorInt int paintColor) {
        float[] radii = getRadii();
        if( radii == null ) return;
        //设置画笔颜色
        mPaint.setColor( paintColor );
        //绘制形状
        mShapePath.reset();
        mShapePath.addRoundRect( mRectF, radii, Path.Direction.CW );
        canvas.drawPath( mShapePath, mPaint );
        drawClipPath( canvas);
    }

    private void drawPath(Canvas canvas) {
        float[] radii = getRadii();
        if( radii == null ) return;
        //清空之前绘制的路径
        mShapePath.reset();
        //绘制形状
        mShapePath.addRoundRect( mRectF, radii, Path.Direction.CW );
        drawClipPath( canvas);
    }

    private void drawClipPath(Canvas canvas) {
        //裁剪路径
        canvas.clipPath( mShapePath, Region.Op.DIFFERENCE );
        //绘制路径
        canvas.drawPath( mShapePath, mPaint );
        mShapePath.reset();
    }

    private void drawBitmap(Canvas canvas, Bitmap bitmap) {
        canvas.drawBitmap( bitmap, (float) 0, (float) 0, mPaint );
    }

    private int getRectWidth(int size) {
        return size == 0 ? getShadowSizeX() : size - getShadowSizeX();
    }

    private int getRectHeight(int size) {
        return size == 0 ? getShadowSizeY() : size - getShadowSizeY();
    }

    private int getShadowSizeX() { return mShadowRadius + mShadowOffsetX; }
    private int getShadowSizeY() { return mShadowRadius + mShadowOffsetY; }

    private Canvas getCanvas() {
        mShapeCanvas.drawColor( Color.TRANSPARENT );
        return mShapeCanvas;
    }

    private void initPaint() {
        mPaint.setColor( Color.TRANSPARENT );
        mPaint.setStrokeWidth( 0 );
        mPaint.setStyle( Paint.Style.FILL );
    }

    private void initRectFOfDefault(Bitmap shapeBmp, int offset) {
        float left = getRectWidth( 0 ) + offset;
        float top = getRectHeight( 0 ) + offset;
        float right = getRectWidth( shapeBmp.getWidth() ) - offset;
        float bottom = getRectHeight( shapeBmp.getHeight() ) - offset;
        mRectF.set( isRtlLayout ? right : left, top, isRtlLayout ? left : right, bottom );
    }

    @NonNull
    private Bitmap getShapeBmp(int width, int height) {
        return Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
    }

    private int getShadowColor(Context context) {
        if( context == null ) return Color.parseColor( "#8FA1A0A1" );
        return mShadowColor != 0 ?
                mShadowColor : context.getResources().getColor( R.color.colorShadow );
    }

    private int paddingHash = 0;
    public synchronized void updatePadding() {
        View v = mWrView.get();
        if( v == null || v instanceof ImageView) return;
        int se = getShadowSizeX() + mBorderSize;
        int tb = getShadowSizeY() + mBorderSize;
        v.setPaddingRelative(
                v.getPaddingStart() + se,
                v.getPaddingTop() + tb,
                v.getPaddingEnd() + se,
                v.getPaddingBottom() + tb
        );
        paddingHash = getPaddingHash();
    }

    private int getPaddingHash() {
        View v = mWrView.get();
        return v == null ? 0 : ( "" +
                v.getPaddingStart() + v.getPaddingTop() +
                v.getPaddingEnd() + v.getPaddingBottom()
        ).hashCode();
    }
//    private Context mContext;
//    private Paint mPaint;
//    private PaintFlagsDrawFilter mDrawFilter;
//    private PorterDuffXfermode mXfermodeIn, mXfermodeOut;
//    private Canvas mShapeCanvas;
//    private RectF mRectF;
//
//    private float mRadius;
//    private int mBorderSize;
//    @ColorInt
//    private int mBorderColor;
//    private int mShadowRadius, mShadowOffsetX, mShadowOffsetY;
//    @ColorInt
//    private int mShadowColor;
//
//    <T extends View> ToastXShapeHelper init(@NonNull T v) {
//        mContext = v.getContext();
//        mPaint = new Paint();
//        //画布抗锯齿
//        mDrawFilter = new PaintFlagsDrawFilter(
//                0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG
//        );
//        mRectF = new RectF();
//        mShapeCanvas = new Canvas();
//        /* 保留上层交集图像 */
//        mXfermodeIn = new PorterDuffXfermode( PorterDuff.Mode.DST_IN );
//        /* 消除上层图像 */
//        mXfermodeOut = new PorterDuffXfermode( PorterDuff.Mode.DST_OUT );
//        //启用抗锯齿
//        mPaint.setAntiAlias( true );
//        //消除画布的抗锯齿
//        mShapeCanvas.setDrawFilter( mDrawFilter );
//        //启用硬件加速，否则会出现一些异常（比如黑边，设计器和模拟器可能依旧会存在黑边）
//        v.setLayerType( View.LAYER_TYPE_HARDWARE, mPaint );
//        return this;
//    }
//
//    @Override
//    public void setRadius(int radius) { mRadius = radius; }
//
//    @Override
//    public void setBorderSize(int borderSize) { mBorderSize = borderSize; }
//    @Override
//    public void setBorderColor(@ColorInt int color) { mBorderColor = color; }
//
//    @Override
//    public void setShadowRadius(int radius) { mShadowRadius = radius; }
//    @Override
//    public void setShadowColor(@ColorInt int color) { mShadowColor = color; }
//    @Override
//    public void setShadowOffsetX(int offsetX) { mShadowOffsetX = offsetX; }
//    @Override
//    public void setShadowOffsetY(int offsetY) { mShadowOffsetY = offsetY; }
//
//    public void dispatchDraw(Canvas canvas, View v) {
//        int width = v.getWidth();
//        int height = v.getHeight();
//        if( width <= 0 || height <= 0 ) {
//            v.measure( 0, 0 );
//            width = v.getMeasuredWidth();
//            height = v.getMeasuredHeight();
//        }
//        if( width <= 0 || height <= 0 ) return;
//
//        //消除画布的抗锯齿
//        canvas.setDrawFilter( mDrawFilter );
//        //获取绘制圆角部分的图片
//        drawShape( canvas, width, height );
//        //绘制阴影
//        drawShadow( canvas, width, height );
//        //绘制描边
//        drawStroke( canvas, width, height );
//    }
//
//    /**
//     * 绘制圆角部分的图片。
//     * @param canvas    画布
//     * @param width     高度
//     * @param height    宽度
//     */
//    private void drawShape(Canvas canvas, int width, int height) {
//        //建立一个空白图片，在里边绘制圆角
//        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
//        Canvas shapeCanvas = getCanvas();
//        //初始化矩形
//        initRectF(
//                mBorderSize,
//                mBorderSize,
//                width - mBorderSize,
//                height - mBorderSize
//        );
//        //设置图片
//        shapeCanvas.setBitmap( shapeBmp );
//        //绘制形状
//        drawShape( shapeCanvas, mRectF );
//        //绘制时消除绘制的圆角(或者注释掉看效果就明白了)
//        mPaint.setXfermode( mXfermodeIn );
//        //绘制最终的结果
//        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
//        mPaint.setXfermode( null );
//    }
//
//    /**
//     * 绘制描边
//     * @param canvas    画布
//     */
//    private void drawStroke(Canvas canvas, int width, int height) {
//        if( mBorderSize == 0 ) return;
//        Canvas strokeCanvas = getCanvas();
//        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
//        //初始化矩形
//        initRectF( 0, 0, width, height );
//        //描边颜色
//        mPaint.setColor( mBorderColor );
//        //设置图片
//        strokeCanvas.setBitmap( shapeBmp );
//        //绘制描边
//        drawShape( strokeCanvas, mRectF );
//
//        /* 绘制空心效果 */
//        mRectF.left += mBorderSize;
//        mRectF.top += mBorderSize;
//        mRectF.right -= mBorderSize;
//        mRectF.bottom -= mBorderSize;
//        mPaint.setXfermode( mXfermodeOut );
//        //绘制空心
//        drawShape( strokeCanvas, mRectF );
//        mPaint.setXfermode( null );
//        //提交最终结果
//        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
//    }
//
//    /**
//     * 绘制阴影
//     * @param canvas    画布
//     */
//    private void drawShadow(Canvas canvas, int width, int height) {
//        if( mShadowRadius == 0 ) return;
//        int color = getShadowColor();
//        Canvas shadowCanvas = getCanvas();
//        Bitmap shapeBmp = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
//        //初始化矩形
//        initRectF( 0, 0, width, height );
//        //设置图片
//        shadowCanvas.setBitmap( shapeBmp );
//        //创建阴影
//        mPaint.setShadowLayer( mShadowRadius, mShadowOffsetX, mShadowOffsetY, color );
//        drawShape( shadowCanvas, mRectF );
//        //关闭阴影
//        mPaint.setShadowLayer( 0F, 0F, 0F, color );
//
//        float dp = Utils.dp2Px( mContext, 0.1F );
//        //初始化矩形
//        initRectF( -dp, -dp, width + dp, height + dp );
//        /* 绘制空心效果 */
//        mPaint.setXfermode( mXfermodeOut );
//        //绘制空心
//        drawShape( shadowCanvas, mRectF );
//        mPaint.setXfermode( null );
//        //提交最终结果
//        canvas.drawBitmap( shapeBmp, 0, 0, mPaint );
//    }
//
//    public Canvas getCanvas() {
//        mShapeCanvas.drawColor( Color.TRANSPARENT );
//        return mShapeCanvas;
//    }
//
//    /**
//     * 绘制形状
//     * @param canvas    画布
//     * @param rectF     形状大小
//     */
//    private void drawShape(Canvas canvas, RectF rectF) {
//        if( mRadius > 0 ) {
//            canvas.drawRoundRect( rectF, mRadius, mRadius, mPaint );
//            return;
//        }
//        canvas.drawRect( rectF, mPaint );
//    }
//
//    private void initRectF(float left, float top, float right, float bottom) {
//        mRectF.set(
//                left + mShadowRadius * 2,
//                top + mShadowRadius * 2,
//                right - mShadowRadius * 2,
//                bottom - mShadowRadius * 2
//        );
//    }
//
//    private int getShadowColor() {
//        if( mContext == null ) return Color.BLACK;
//        return mShadowColor != 0 ?
//                mShadowColor :
//                mContext.getResources().getColor( R.color.colorShadow );
//    }
}
